// Multer 文件上传中间件中文API封装
const multer = require('multer');
const fs = require('fs');
const path = require('path');

/**
 * 创建存储引擎
 * @param {Object} 选项 - 存储引擎配置选项
 * @returns {Object} Multer存储引擎
 */
function 创建存储引擎(选项 = {}) {
  const { 
    目标目录 = 'uploads',
    文件名生成器 = (请求, 文件, 回调) => {
      const 唯一后缀 = Date.now() + '-' + Math.round(Math.random() * 1E9);
      callback(null, file.fieldname + '-' + 唯一后缀 + path.extname(file.originalname));
    },
    文件过滤 = null
  } = 选项;
  
  // 确保上传目录存在
  if (!fs.existsSync(目标目录)) {
    fs.mkdirSync(目标目录, { recursive: true });
  }
  
  const 存储选项 = {
    destination: 目标目录,
    filename: 文件名生成器
  };
  
  return multer.diskStorage(存储选项);
}

/**
 * 创建Multer实例
 * @param {Object} 配置 - Multer配置选项
 * @returns {Object} Multer实例
 */
function 创建上传器(配置 = {}) {
  const { 
    存储引擎 = null,
    限制 = {
      文件大小: 10 * 1024 * 1024, // 默认10MB
    },
    文件过滤 = null,
    保留原始扩展名 = false
  } = 配置;
  
  const multer配置 = {};
  
  if (存储引擎) {
    multer配置.storage = 存储引擎;
  }
  
  if (限制) {
    multer配置.limits = 限制;
  }
  
  if (文件过滤) {
    multer配置.fileFilter = 文件过滤;
  }
  
  // 处理保留原始扩展名选项
  if (保留原始扩展名 && !multer配置.storage) {
    // 如果没有提供存储引擎但需要保留原始扩展名，则创建默认存储
    multer配置.storage = 创建存储引擎();
  }
  
  return multer(multer配置);
}

/**
 * 创建单个文件上传中间件
 * @param {Object} 上传器 - Multer实例
 * @param {string} 字段名 - 表单字段名称
 * @param {Object} 选项 - 可选配置
 * @returns {Function} Express中间件
 */
function 单文件上传(上传器, 字段名, 选项 = {}) {
  return 上传器.single(字段名);
}

/**
 * 创建多个文件上传中间件
 * @param {Object} 上传器 - Multer实例
 * @param {string} 字段名 - 表单字段名称
 * @param {number} 最大数量 - 最大文件数量
 * @returns {Function} Express中间件
 */
function 多文件上传(上传器, 字段名, 最大数量) {
  return 上传器.array(字段名, 最大数量);
}

/**
 * 创建多字段文件上传中间件
 * @param {Object} 上传器 - Multer实例
 * @param {Array} 字段配置 - 字段配置数组 [{name: '字段名', maxCount: 最大数量}, ...]
 * @returns {Function} Express中间件
 */
function 多字段上传(上传器, 字段配置) {
  return 上传器.fields(字段配置);
}

/**
 * 上传所有文件中间件
 * @param {Object} 上传器 - Multer实例
 * @returns {Function} Express中间件
 */
function 上传所有文件(上传器) {
  return 上传器.any();
}

/**
 * 不处理文件上传
 * @param {Object} 上传器 - Multer实例
 * @returns {Function} Express中间件
 */
function 不处理文件(上传器) {
  return 上传器.none();
}

/**
 * 创建图片文件过滤函数
 * @param {Array} 允许的格式 - 允许的图片格式数组
 * @returns {Function} 文件过滤函数
 */
function 创建图片过滤(允许的格式 = ['jpg', 'jpeg', 'png', 'gif', 'webp']) {
  return function(请求, 文件, 回调) {
    // 检查文件扩展名
    const 文件扩展名 = path.extname(file.originalname).toLowerCase().slice(1);
    
    // 检查MIME类型
    const 文件MIME类型 = file.mimetype;
    const 是否为图片 = 文件MIME类型.startsWith('image/');
    
    if (是否为图片 && 允许的格式.includes(文件扩展名)) {
      return 回调(null, true);
    } else {
      return 回调(new Error(`只允许上传以下格式的图片: ${允许的格式.join(', ')}`), false);
    }
  };
}

/**
 * 创建视频文件过滤函数
 * @param {Array} 允许的格式 - 允许的视频格式数组
 * @returns {Function} 文件过滤函数
 */
function 创建视频过滤(允许的格式 = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv']) {
  return function(请求, 文件, 回调) {
    // 检查文件扩展名
    const 文件扩展名 = path.extname(file.originalname).toLowerCase().slice(1);
    
    // 检查MIME类型
    const 文件MIME类型 = file.mimetype;
    const 是否为视频 = 文件MIME类型.startsWith('video/');
    
    if (是否为视频 && 允许的格式.includes(文件扩展名)) {
      return 回调(null, true);
    } else {
      return 回调(new Error(`只允许上传以下格式的视频: ${允许的格式.join(', ')}`), false);
    }
  };
}

/**
 * 创建文档文件过滤函数
 * @param {Array} 允许的格式 - 允许的文档格式数组
 * @returns {Function} 文件过滤函数
 */
function 创建文档过滤(允许的格式 = ['pdf', 'doc', 'docx', 'txt', 'xls', 'xlsx', 'ppt', 'pptx']) {
  return function(请求, 文件, 回调) {
    // 检查文件扩展名
    const 文件扩展名 = path.extname(file.originalname).toLowerCase().slice(1);
    
    if (允许的格式.includes(文件扩展名)) {
      return 回调(null, true);
    } else {
      return 回调(new Error(`只允许上传以下格式的文档: ${允许的格式.join(', ')}`), false);
    }
  };
}

/**
 * 创建自定义文件过滤函数
 * @param {Array} 允许的扩展名 - 允许的文件扩展名数组
 * @param {Array} 允许的MIME类型 - 允许的MIME类型数组
 * @returns {Function} 文件过滤函数
 */
function 创建自定义文件过滤(允许的扩展名 = [], 允许的MIME类型 = []) {
  return function(请求, 文件, 回调) {
    // 检查文件扩展名
    const 文件扩展名 = path.extname(file.originalname).toLowerCase().slice(1);
    
    // 检查MIME类型
    const 文件MIME类型 = file.mimetype;
    
    // 如果扩展名或MIME类型匹配任一允许的类型，则允许上传
    const 扩展名匹配 = 允许的扩展名.length === 0 || 允许的扩展名.includes(文件扩展名);
    const MIME类型匹配 = 允许的MIME类型.length === 0 || 
                          允许的MIME类型.some(type => 文件MIME类型 === type || 文件MIME类型.startsWith(type + '/'));
    
    if (扩展名匹配 && MIME类型匹配) {
      return 回调(null, true);
    } else {
      return 回调(new Error(`不允许的文件类型。允许的扩展名: ${允许的扩展名.join(', ') || '任意'}。允许的MIME类型: ${允许的MIME类型.join(', ') || '任意'}`), false);
    }
  };
}

/**
 * 生成唯一文件名
 * @param {string} 前缀 - 文件名前缀
 * @returns {Function} 文件名生成函数
 */
function 生成唯一文件名(前缀 = '') {
  return function(请求, 文件, 回调) {
    const 唯一ID = Date.now() + '-' + Math.round(Math.random() * 1E9);
    const 文件扩展名 = path.extname(file.originalname);
    const 最终前缀 = 前缀 ? 前缀 + '-' : '';
    callback(null, 最终前缀 + 唯一ID + 文件扩展名);
  };
}

/**
 * 保留原始文件名（添加时间戳避免冲突）
 * @returns {Function} 文件名生成函数
 */
function 保留原始文件名() {
  return function(请求, 文件, 回调) {
    const 文件扩展名 = path.extname(file.originalname);
    const 文件名 = path.basename(file.originalname, 文件扩展名);
    // 移除特殊字符
    const 安全文件名 = 文件名.replace(/[^a-zA-Z0-9_-]/g, '_');
    callback(null, 安全文件名 + '-' + Date.now() + 文件扩展名);
  };
}

/**
 * 根据用户ID生成上传目录
 * @param {string} 基础目录 - 基础上传目录
 * @returns {Object} 存储引擎配置
 */
function 根据用户ID创建目录(基础目录 = 'uploads') {
  return {
    destination: function(请求, 文件, 回调) {
      // 假设用户ID存储在请求对象中
      const 用户ID = 请求.user?.id || 'anonymous';
      const 用户目录 = path.join(基础目录, 用户ID.toString());
      
      // 确保目录存在
      if (!fs.existsSync(用户目录)) {
        fs.mkdirSync(用户目录, { recursive: true });
      }
      
      callback(null, 用户目录);
    }
  };
}

/**
 * 根据日期创建上传目录
 * @param {string} 基础目录 - 基础上传目录
 * @returns {Object} 存储引擎配置
 */
function 根据日期创建目录(基础目录 = 'uploads') {
  return {
    destination: function(请求, 文件, 回调) {
      const 现在 = new Date();
      const 年份 = 现在.getFullYear();
      const 月份 = String(现在.getMonth() + 1).padStart(2, '0');
      const 日期 = String(现在.getDate()).padStart(2, '0');
      
      const 日期目录 = path.join(基础目录, 年份.toString(), 月份, 日期);
      
      // 确保目录存在
      if (!fs.existsSync(日期目录)) {
        fs.mkdirSync(日期目录, { recursive: true });
      }
      
      callback(null, 日期目录);
    }
  };
}

/**
 * 获取上传文件信息
 * @param {Object} 请求 - Express请求对象
 * @returns {Object} 文件信息对象
 */
function 获取上传文件信息(请求) {
  const 文件信息 = {};
  
  // 处理单个文件
  if (请求.file) {
    文件信息.单个文件 = {
      字段名: 请求.file.fieldname,
      原始文件名: 请求.file.originalname,
      存储文件名: 请求.file.filename,
      文件路径: 请求.file.path,
      MIME类型: 请求.file.mimetype,
      文件大小: 请求.file.size,
      文件扩展名: path.extname(request.file.originalname).toLowerCase()
    };
  }
  
  // 处理多个文件
  if (请求.files && Array.isArray(请求.files)) {
    文件信息.多个文件 = 请求.files.map(file => ({
      字段名: file.fieldname,
      原始文件名: file.originalname,
      存储文件名: file.filename,
      文件路径: file.path,
      MIME类型: file.mimetype,
      文件大小: file.size,
      文件扩展名: path.extname(file.originalname).toLowerCase()
    }));
  }
  
  // 处理多字段文件
  if (请求.files && !Array.isArray(请求.files)) {
    文件信息.多字段文件 = {};
    Object.keys(request.files).forEach(字段名 => {
      文件信息.多字段文件[字段名] = request.files[字段名].map(file => ({
        原始文件名: file.originalname,
        存储文件名: file.filename,
        文件路径: file.path,
        MIME类型: file.mimetype,
        文件大小: file.size,
        文件扩展名: path.extname(file.originalname).toLowerCase()
      }));
    });
  }
  
  return 文件信息;
}

/**
 * 创建文件上传错误处理中间件
 * @returns {Function} 错误处理中间件
 */
function 创建上传错误处理中间件() {
  return function(错误, 请求, 响应, 下一个) {
    if (错误 instanceof multer.MulterError) {
      // Multer错误
      let 错误消息 = '';
      
      switch (错误.code) {
        case 'LIMIT_FILE_SIZE':
          错误消息 = '文件大小超出限制';
          break;
        case 'LIMIT_FILE_COUNT':
          错误消息 = '文件数量超出限制';
          break;
        case 'LIMIT_PART_COUNT':
          错误消息 = '请求部分数量超出限制';
          break;
        case 'LIMIT_FIELD_KEY':
          错误消息 = '字段名过长';
          break;
        case 'LIMIT_FIELD_VALUE':
          错误消息 = '字段值过长';
          break;
        case 'LIMIT_FIELD_COUNT':
          错误消息 = '字段数量超出限制';
          break;
        case 'LIMIT_UNEXPECTED_FILE':
          错误消息 = '接收到意外的文件';
          break;
        default:
          错误消息 = '文件上传错误: ' + 错误.message;
      }
      
      return 响应.status(400).json({
        成功: false,
        错误: 错误消息,
        错误代码: 错误.code
      });
    } else if (错误) {
      // 其他错误（如文件类型过滤错误）
      return 响应.status(400).json({
        成功: false,
        错误: 错误.message || '文件上传失败'
      });
    }
    
    // 没有错误，继续处理请求
    下一个();
  };
}

/**
 * 创建限制文件大小的选项
 * @param {number} 最大大小MB - 最大文件大小（MB）
 * @returns {Object} 限制选项对象
 */
function 创建文件大小限制(最大大小MB) {
  return {
    fileSize: 最大大小MB * 1024 * 1024 // 转换为字节
  };
}

/**
 * 检查文件是否存在
 * @param {string} 文件路径 - 文件完整路径
 * @returns {boolean} 文件是否存在
 */
function 检查文件是否存在(文件路径) {
  return fs.existsSync(文件路径);
}

/**
 * 删除上传的文件
 * @param {string} 文件路径 - 文件完整路径
 * @returns {boolean} 是否删除成功
 */
function 删除上传文件(文件路径) {
  try {
    if (fs.existsSync(文件路径)) {
      fs.unlinkSync(文件路径);
      return true;
    }
    return false;
  } catch (错误) {
    console.error('删除文件失败:', 错误);
    return false;
  }
}

/**
 * 生成文件访问URL
 * @param {Object} 文件 - 文件对象
 * @param {string} 基础URL - 基础URL
 * @param {string} 路由前缀 - 路由前缀
 * @returns {string} 文件访问URL
 */
function 生成文件访问URL(文件, 基础URL = '', 路由前缀 = '/uploads') {
  if (!文件 || !文件.filename) return '';
  
  // 获取文件相对路径（去除基础上传目录）
  const 完整路径 = file.path;
  const 文件名 = file.filename;
  let 相对路径 = '';
  
  // 尝试从完整路径中提取相对路径
  const 路径部分 = 完整路径.split(path.sep);
  const 文件索引 = 路径部分.indexOf(文件名);
  
  if (文件索引 !== -1) {
    // 构建相对路径
    相对路径 = 路径部分.slice(file索引).join('/');
  } else {
    相对路径 = 文件名;
  }
  
  // 确保URL格式正确
  const 清理后的路由前缀 = 路由前缀.replace(/^\/+|\/+$/g, '');
  const 清理后的基础URL = 基础URL.replace(/\/+$/, '');
  
  return `${清理后的基础URL}/${清理后的路由前缀}/${相对路径}`;
}

/**
 * 创建预配置的图片上传器
 * @param {Object} 选项 - 配置选项
 * @returns {Object} 配置好的上传器和中间件
 */
function 创建图片上传器(选项 = {}) {
  const { 
    上传目录 = 'uploads/images',
    最大文件大小 = 5, // MB
    允许的格式 = ['jpg', 'jpeg', 'png', 'gif', 'webp'],
    保留原始名称 = false
  } = 选项;
  
  // 创建存储引擎
  const 存储配置 = {
    目标目录: 上传目录,
    文件名生成器: 保留原始名称 ? 保留原始文件名() : 生成唯一文件名('img')
  };
  
  // 如果使用按日期分类的目录
  if (选项.按日期分类) {
    const 日期目录配置 = 根据日期创建目录(上传目录);
    存储配置.目标目录 = 日期目录配置.destination;
  }
  
  const 存储引擎 = 创建存储引擎(存储配置);
  
  // 创建上传器
  const 上传器 = 创建上传器({
    存储引擎: 存储引擎,
    限制: 创建文件大小限制(最大文件大小),
    文件过滤: 创建图片过滤(允许的格式)
  });
  
  return {
    上传器: 上传器,
    单文件上传: (字段名 = '图片') => 单文件上传(上传器, 字段名),
    多文件上传: (字段名 = '图片', 最大数量 = 10) => 多文件上传(上传器, 字段名, 最大数量),
    错误处理中间件: 创建上传错误处理中间件()
  };
}

/**
 * 创建预配置的文档上传器
 * @param {Object} 选项 - 配置选项
 * @returns {Object} 配置好的上传器和中间件
 */
function 创建文档上传器(选项 = {}) {
  const { 
    上传目录 = 'uploads/documents',
    最大文件大小 = 20, // MB
    允许的格式 = ['pdf', 'doc', 'docx', 'txt', 'xls', 'xlsx', 'ppt', 'pptx'],
    保留原始名称 = true
  } = 选项;
  
  // 创建存储引擎
  const 存储配置 = {
    目标目录: 上传目录,
    文件名生成器: 保留原始名称 ? 保留原始文件名() : 生成唯一文件名('doc')
  };
  
  const 存储引擎 = 创建存储引擎(存储配置);
  
  // 创建上传器
  const 上传器 = 创建上传器({
    存储引擎: 存储引擎,
    限制: 创建文件大小限制(最大文件大小),
    文件过滤: 创建文档过滤(允许的格式)
  });
  
  return {
    上传器: 上传器,
    单文件上传: (字段名 = '文档') => 单文件上传(上传器, 字段名),
    多文件上传: (字段名 = '文档', 最大数量 = 5) => 多文件上传(上传器, 字段名, 最大数量),
    错误处理中间件: 创建上传错误处理中间件()
  };
}

/**
 * 创建预配置的视频上传器
 * @param {Object} 选项 - 配置选项
 * @returns {Object} 配置好的上传器和中间件
 */
function 创建视频上传器(选项 = {}) {
  const { 
    上传目录 = 'uploads/videos',
    最大文件大小 = 100, // MB
    允许的格式 = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv'],
    保留原始名称 = false
  } = 选项;
  
  // 创建存储引擎
  const 存储配置 = {
    目标目录: 上传目录,
    文件名生成器: 保留原始名称 ? 保留原始文件名() : 生成唯一文件名('video')
  };
  
  const 存储引擎 = 创建存储引擎(存储配置);
  
  // 创建上传器
  const 上传器 = 创建上传器({
    存储引擎: 存储引擎,
    限制: 创建文件大小限制(最大文件大小),
    文件过滤: 创建视频过滤(允许的格式)
  });
  
  return {
    上传器: 上传器,
    单文件上传: (字段名 = '视频') => 单文件上传(上传器, 字段名),
    多文件上传: (字段名 = '视频', 最大数量 = 3) => 多文件上传(上传器, 字段名, 最大数量),
    错误处理中间件: 创建上传错误处理中间件()
  };
}

module.exports = {
  // 核心函数
  创建上传器,
  创建存储引擎,
  
  // 上传中间件
  单文件上传,
  多文件上传,
  多字段上传,
  上传所有文件,
  不处理文件,
  
  // 文件过滤
  创建图片过滤,
  创建视频过滤,
  创建文档过滤,
  创建自定义文件过滤,
  
  // 文件名生成
  生成唯一文件名,
  保留原始文件名,
  
  // 目录管理
  根据用户ID创建目录,
  根据日期创建目录,
  
  // 工具函数
  获取上传文件信息,
  创建上传错误处理中间件,
  创建文件大小限制,
  检查文件是否存在,
  删除上传文件,
  生成文件访问URL,
  
  // 预配置上传器
  创建图片上传器,
  创建文档上传器,
  创建视频上传器,
  
  // 获取原始模块
  获取原始Multer: () => multer,
  
  // 常量
  文件类型: {
    图片: ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'svg'],
    视频: ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm'],
    文档: ['pdf', 'doc', 'docx', 'txt', 'xls', 'xlsx', 'ppt', 'pptx', 'csv'],
    压缩包: ['zip', 'rar', '7z', 'tar', 'gz']
  },
  
  // Multer错误代码
  错误代码: {
    文件大小超限: 'LIMIT_FILE_SIZE',
    文件数量超限: 'LIMIT_FILE_COUNT',
    请求部分数量超限: 'LIMIT_PART_COUNT',
    字段名过长: 'LIMIT_FIELD_KEY',
    字段值过长: 'LIMIT_FIELD_VALUE',
    字段数量超限: 'LIMIT_FIELD_COUNT',
    意外文件: 'LIMIT_UNEXPECTED_FILE'
  }
};